Matrix.Scale = function (x, y, z){
    return $M([
        [x, 0, 0, 0],
        [0, y, 0, 0],
        [0, 0, z, 0],
        [0, 0, 0, 1],
        ]);
};


var mvMatrix;
var mvMatrixStack = [];

function mvPushMatrix(m) {
  if (m) {
    mvMatrixStack.push(m.dup());
    mvMatrix = m.dup();
  } else {
    mvMatrixStack.push(mvMatrix.dup());
  }
}

function createRotationMatrix(angle, v) {
    var arad = angle * Math.PI / 180.0;
    return Matrix.Rotation(arad, $V([v[0], v[1], v[2]])).ensure4x4();
  }

function mvPopMatrix() {
	if (mvMatrixStack.length == 0) {
		throw "Invalid popMatrix!";
	}
	mvMatrix = mvMatrixStack.pop();
	return mvMatrix;
}

function loadIdentity() {
  mvMatrix = Matrix.I(4);
}


function multMatrix(m) {
	mvMatrix = mvMatrix.x(m);	
}

function mvTranslate(v) {
	var m = Matrix.Translation($V([v[0], v[1], v[2]])).ensure4x4();
	multMatrix(m);
}

function mvRotate(ang, v) {
	var arad = ang * Math.PI / 180.0;
	var m = Matrix.Rotation(arad, $V([v[0], v[1], v[2]])).ensure4x4();
	multMatrix(m);
}

function mvRotateRad(rad,v)
{
	var m = Matrix.Rotation(rad, $V([v[0], v[1], v[2]])).ensure4x4();
	multMatrix(m);
}

function mvScale(v){
    var m = Matrix.Scale(v[0], v[1], v[2]);
    multMatrix(m);
}

var pMatrix;
function perspective(fovy, aspect, znear, zfar) {
	pMatrix = makePerspective(fovy, aspect, znear, zfar);
}


function setMatrixUniforms(gl, shaderProgram) {
	gl.uniformMatrix4fv(shaderProgram.pMatrixUniform, false, new Float32Array(pMatrix.flatten()));
	gl.uniformMatrix4fv(shaderProgram.mvMatrixUniform, false, new Float32Array(mvMatrix.flatten()));
	
    var normalMatrix = mvMatrix.inverse();
    if (normalMatrix) {
	    normalMatrix = normalMatrix.transpose();
	    gl.uniformMatrix4fv(shaderProgram.nMatrixUniform, false, new Float32Array(normalMatrix.flatten()));
    }
}
